import random
from websocket_util import *
from fastapi import FastAPI, BackgroundTasks
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
import datetime
import os
import requests
from typing import Optional
from apscheduler.schedulers.background import BackgroundScheduler
from websocket_cls import VolumeParam, TaskParam
from pydub import AudioSegment
"""
pip install websockets
pip install fastapi
pip install "uvicorn[standard]"
pip install apscheduler 
pip install requests
pip install python-dotenv
pip install pydantic-settings
pip install pydub
启动：uvicorn websocket_main:app --reload
打包：pyinstaller -F -c websocket_main.py
打包设置：websocket_main.spec文件的pathex=['D:/06git/01python/ws_dh/server']
执行：pyinstaller websocket_main.spec

Linux运行：nohup python3 -u xxx.py >> xxx.txt 2>&1 &
API：http://127.0.0.1:8000/docs#/
"""

time_limit = datetime.timedelta(seconds=3)
app = FastAPI()
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 允许所有来源
    allow_credentials=True,
    allow_methods=["*"],  # 允许所有方法
    allow_headers=["*"],  # 允许所有头部
)
ws = None


@app.get("/")
def read_root():
    return {"data": "hello world"}


# http://127.0.0.1:8000/items/7788?q=somestr
@app.get("/items/{item_id}")
def get_item(item_id: int, q: Optional[str] = None):
    return {"item_id": item_id, "q": q}


@app.get("/ws/login")
def login():
    """
    登录操作
    :return:
    """
    now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    print('时间：{}, 执行登录操作！'.format(now))
    params = {
        "userName": WS_USERNAME,
        "password": WS_PASSWORD
    }
    msg = {
        "method": "systemManager.login",
        "params": params
    }
    paramData = {
        "cmd": "send",
        "msg": json.dumps(msg)
    }
    ws.wsObj.send(json.dumps(paramData))
    return {"message": "success"}


@app.get("/ws/getDeviceExtra")
def getDeviceExtra():
    """
    查询设备信息
    :return:
    """
    params = {
        "loginHandle": ws.loginHandle,
        "deviceId": 0
    }
    msg = {
        "method": "deviceManager.getDeviceExtra",
        "id": random.randint(1000, 9999),
        "params": params
    }
    paramData = {
        "cmd": "send",
        "msg": json.dumps(msg)
    }
    ws.wsObj.send(json.dumps(paramData))
    return {"message": "success", "data": ws.loginHandle}


@app.get("/ws/getAudioFileList")
def getAudioFileList():
    """
    获取文件列表
    :return:
    """
    params = {
        "loginHandle": ws.loginHandle
    }
    msg = {
        "method": "audioManager.getAudioFileList",
        "id": random.randint(1000, 9999),
        "params": params
    }
    paramData = {
        "cmd": "send",
        "msg": json.dumps(msg)
    }
    ws.wsObj.send(json.dumps(paramData))
    return {"message": "success", "data": ws.loginHandle}


@app.get("/ws/uploadAudioFile")
async def uploadAudioFile(file_name: str, file_url: str, backgroundTasks: BackgroundTasks):
    """
    上传文件
    :param file_name: 文件名称（test.mp3）
    :param file_url: 文件路径（http://10.10.50.89:30100/download/test.mp3）
    :return:
    """
    backgroundTasks.add_task(uploadAudioFileAsync, file_name, file_url)
    return {"message": "success"}


async def uploadAudioFileAsync(file_name: str, file_url: str):
    """
    异步上传
    :param file_name: 2025测试文件.mp3
    :param file_url: /broadcastMedia/成都20230906155304.mp3
    :return:
    """
    if not file_url.startswith("http"):
        file_url = File_URL_PREFIX + file_url
    project_root = os.getcwd()
    path = project_root + "/upload_file"
    create_dir(path)
    file_path = path + "/" + file_name
    r = requests.get(file_url)
    with open(file_path, "wb") as code:
        code.write(r.content)
    audio = AudioSegment.from_file(file_path)
    #audio = audio.set_frame_rate(16000)
    #audio.export(file_path, format="mp3")
    #audio.export(file_path, format="wav", parameters=["-acodec", "pcm_s16le"])

    audio = audio.set_frame_rate(16000)  # 设置采样率
    #audio = audio.set_sample_width(2)  # 设置量化位数为16位（2字节）
    audio = audio.set_channels(1)  # 设置为单声道（1声道）
    # 保存为MP3文件
    audio.export(file_path, format="wav", parameters=["-acodec", "pcm_s16le"])
    #audio.export(file_path, format="mp3", bitrate="128k")  # 设置比特率为64kbps


    file_size = os.path.getsize(file_path)
    sampleRate = audio.frame_rate
    print("采样率为：",str(sampleRate))
    print("音频大小为：", len(audio.raw_data))
    params = {
        "loginHandle": ws.loginHandle,
        "file": {
            "name": file_name,
            "length": file_size,
            "sampleRate": sampleRate,
            "bitsPerSec": 128,
            "encode": "pcm"
        }
    }
    upload_id = random.randint(1000, 9999)
    msg = {
        "method": "audioManager.uploadAudioFile",
        "id": upload_id,
        "params": params
    }
    param_upload_data = {
        "cmd": "send",
        "msg": json.dumps(msg, ensure_ascii=False)
    }
    ws.wsObj.send(json.dumps(param_upload_data))

    start_command_time = datetime.datetime.now()
    upload_command_flag = False
    while True:
        current_command_time = datetime.datetime.now()
        if CACHE.get(upload_id):
            print("收到发送成功指令，开始上传文件")
            upload_command_flag = True
            break
        elif current_command_time - start_command_time > time_limit:
            print("发送文件{}超时退出".format(file_name))
            break
        else:
            time.sleep(0.5)

    if upload_command_flag:
        ws_upload_file = WebsocketServiceUploadFile(WS_URL, ws.loginHandle, ws.clientid)
        ws_upload_file.start()
        start_time = datetime.datetime.now()
        with open(file_path, "rb") as f:
            while True:
                current_time = datetime.datetime.now()
                if ws_upload_file.open_flag:
                    audio_data = f.read(640)
                    if not audio_data:
                        ws_upload_file.wsObj.send("OVER")
                        time.sleep(1)
                        ws_upload_file.wsObj.close()
                        f.close()
                        break
                    ws_upload_file.wsObj.send(audio_data)
                    time.sleep(0.0005)
                elif current_time - start_time > time_limit:
                    print("发送文件{}超时退出".format(file_name))
                    f.close()
                    break
                else:
                    time.sleep(0.5)
    # 上传完成调用获取文件列表
    getAudioFileList()
    return None

@app.delete("/ws/deleteAudioFile/{filedId}")
def deleteAudioFile(filedId: int):
    """
    删除音频文件
    :param filedId:文件ID
    :return:
    """
    params = {
        "loginHandle": ws.loginHandle,
        "fileId": filedId
    }
    msg = {
        "method": "audioManager.deleteAudioFile",
        "id": random.randint(1000, 9999),
        "params": params
    }
    paramData = {
        "cmd": "send",
        "msg": json.dumps(msg, ensure_ascii=False)
    }
    ws.wsObj.send(json.dumps(paramData))
    return {"message": "success"}


def create_dir(dir):
    """
    检查目录是否存在
    :param dir:
    :return:
    """
    if not os.path.exists(dir):
        os.makedirs(dir)
    return None


@app.post("/ws/uploadOrEditBCTask")
def uploadOrEditBCTask(taskParam: TaskParam):
    """
    接收定时广播任务和实时广播任务
    :param taskParam: 参数
    :return:
    """
    print(json.dumps(taskParam, default=taskParam.jsonformat, ensure_ascii=False))
    id = random.randint(1000, 9999)
    task = {
        "id": None if taskParam.taskId == None else taskParam.taskId,
        "fileIds": taskParam.fileIds,
        "deviceIds": taskParam.deviceIds,
        "name": taskParam.taskName,
        "volume": taskParam.volume,
        "expire": {
            "enable": taskParam.expireObj.enable,
            "beginDate": taskParam.expireObj.beginDate,
            "endDate": taskParam.expireObj.enable
        },
        "enable": taskParam.enable,
        "duration": {
            "enable": True if taskParam.timeMode == "seconds" else False,
            "seconds": taskParam.modeContent if taskParam.timeMode == "seconds" else 0
        },
        "loop": {
            "enable": True if taskParam.timeMode == "times" else False,
            "times": taskParam.modeContent if taskParam.timeMode == "times" else 0
        },
        "execMode": taskParam.execMode,
        "weekDay": taskParam.weekDay,
        "startTimeOfDay": taskParam.startTimeOfDay,
        "taskType": taskParam.taskType,
        "bcType": taskParam.bcType
    }
    params = {
        "loginHandle": ws.loginHandle,
        "id": id,
        "task": task
    }
    msg = {
        "method": "audioManager.uploadBCTask" if taskParam.taskId == None else "audioManager.editBCTask",
        "id": id,
        "params": params
    }
    paramData = {
        "cmd": "send",
        "msg": json.dumps(msg, ensure_ascii=False)
    }
    ws.wsObj.send(json.dumps(paramData))
    return {"message": "success"}


@app.delete("/ws/deleteBCTask/{taskId}")
def deleteBCTask(taskId: int):
    """
    删除广播任务
    :param taskId:任务ID
    :return:
    """
    params = {
        "loginHandle": ws.loginHandle,
        "taskId": taskId
    }
    msg = {
        "method": "audioManager.deleteBCTask",
        "id": random.randint(1000, 9999),
        "params": params
    }
    paramData = {
        "cmd": "send",
        "msg": json.dumps(msg, ensure_ascii=False)
    }
    ws.wsObj.send(json.dumps(paramData))
    return {"message": "success"}


@app.post("/ws/setDeviceVolume")
def setDeviceVolume(volumeParam: VolumeParam):
    """
    设置设备音量
    :param deviceId: 设备ID
    :param type: 音量类型（input: 麦克风音量，output：喇叭音量）
    :param volume: 设备音量，数组类型(0-100)
    :return:
    """
    tunnelData = {
        "id": random.randint(1000, 9999),
        "method": "configManager.setConfig",
        "name": "AudioInputVolume" if volumeParam.type == "input" else "AudioOutputVolume",
        "deviceId": volumeParam.deviceId,
        "params": volumeParam.volume
    }
    params = {
        "loginHandle": ws.loginHandle,
        "deviceId": volumeParam.deviceId,
        "tunnelData": json.dumps(tunnelData),
    }
    msg = {
        "method": "deviceManager.configTunnel",
        "params": params
    }
    paramData = {
        "cmd": "send",
        "msg": json.dumps(msg, ensure_ascii=False)
    }
    ws.wsObj.send(json.dumps(paramData))
    return {"message": "success"}


@app.get("/ws/editDevice")
def editDevice(deviceId: int, deviceName: str, deviceContact: Optional[str] = None, devicePhone: Optional[str] = None):
    """
    编辑设备
    :param deviceId:设备ID
    :param deviceName:设备名称
    :param deviceContact:设备联系人
    :param devicePhone:设备联系电话
    :return:
    """
    params = {
        "loginHandle": ws.loginHandle,
        "deviceId": deviceId,
        "deviceName": deviceName,
        "deviceContact": deviceContact,
        "devicePhone": devicePhone
    }
    msg = {
        "method": "configManager.editDevice",
        "id": random.randint(1000, 9999),
        "params": params
    }
    paramData = {
        "cmd": "send",
        "msg": json.dumps(msg, ensure_ascii=False)
    }
    ws.wsObj.send(json.dumps(paramData))
    return {"message": "success"}


@app.get("/ws/tryBCTask/{taskId}/{action}")
def tryBCTask(taskId: int, action: str):
    """
    试听广播任务
    :param taskId:
    :param action: start/stop
    :return:
    """
    print("试听广播任务")
    params = {
        "loginHandle": ws.loginHandle,
        "taskId": taskId,
        "action": action
    }
    msg = {
        "method": "audioManager.tryBCTask",
        "id": random.randint(1000, 9999),
        "params": params
    }
    paramData = {
        "cmd": "send",
        "msg": json.dumps(msg)
    }
    ws.wsObj.send(json.dumps(paramData))
    return {"message": "success"}


@app.get("/ws/getBCTaskList")
def getBCTaskList(taskType: Optional[str] = "timed"):
    """
    获取广播任务列表
    :param taskType:任务类型（realtime：实时任务，timed：定时任务）默认值：timed
    :return:
    """
    print("获取广播任务列表")
    params = {
        "loginHandle": ws.loginHandle,
        "taskType": taskType
    }
    msg = {
        "method": "audioManager.getBCTaskList",
        "id": random.randint(1000, 9999),
        "params": params
    }
    paramData = {
        "cmd": "send",
        "msg": json.dumps(msg)
    }
    ws.wsObj.send(json.dumps(paramData))
    return {"message": "success"}


@app.on_event('startup')
async def startup():
    global ws
    print("监听启动事件...........")
    ws = WebsocketService(WS_URL)
    ws.start()
    # 启动一个定时任务进行定时获取设备状态的数据
    backtask = BackgroundScheduler(timezone='Asia/Shanghai')
    backtask.add_job(func=login, trigger='cron', minute='*/5',
                     next_run_time=(datetime.datetime.now() + datetime.timedelta(seconds=60)))
    backtask.start()


if __name__ == "__main__":
    uvicorn.run(app=app, host="127.0.0.1", port=8001)